#define _GNU_SOURCE /* Usamos stream_memopen */
#include <check.h>
#include "test_kernel_info.h"

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kernel_info.h"

static KernelInfo *info; /* Compartida por los tests... */
static char *output = NULL;
static size_t output_len = 0;
FILE *outf = NULL;

static void setup (void) {
	info = NULL;
	output = NULL;
	output_len = 0;
	outf = open_memstream (&output, &output_len);
}

static void teardown (void) {
	if (info != NULL)
		kernel_info_destroy (info);
	if (outf != NULL)
		fclose (outf);
	if (output != NULL) {
		free (output);
		output = NULL;
	}
}

/* Testeo de precondiciones */
START_TEST (test_new_null)
{
	info = kernel_info_new (NULL);
}
END_TEST

/* Testeo de funcionalidad */

START_TEST (test_destroy)
{
	KernelInfo *info = kernel_info_new ("kernelinfo/full");
	kernel_info_destroy (info);
}
END_TEST

START_TEST (test_simple_characters_pass)
{
	const char *test_string = "abcde1234!@#,./ \n"; /* Sin $ */
	info = kernel_info_new ("kernelinfo/full");
	kernel_info_print (info, outf, test_string);
	fclose(outf); outf = NULL;
	
	fail_unless (strcmp (output, test_string) == 0);
}
END_TEST

START_TEST (test_unknowns_pass)
{
	const char *test_string = "Not expanded: $notexpanded$\n";
	info = kernel_info_new ("kernelinfo/full");
	kernel_info_print (info, outf, test_string);
	fclose(outf); outf = NULL;
	
	fail_unless (strcmp (output, test_string) == 0);
}
END_TEST

START_TEST (test_double_dollar)
{
	info = kernel_info_new ("kernelinfo/full");
	kernel_info_print (info, outf, "My $$0.02");
	fclose(outf); outf = NULL;
	
	fail_unless (strcmp (output, "My $0.02") == 0);
}
END_TEST

START_TEST (test_substitute)
{
	info = kernel_info_new ("kernelinfo/full");
	kernel_info_print (info, outf, "cpu type $cpu_type$");
	fclose(outf); outf = NULL;
	
	fail_unless (strcmp (output, "cpu type AuthenticAMD") == 0);
}
END_TEST

START_TEST (test_substitute_multiple)
{
	info = kernel_info_new ("kernelinfo/full");
	kernel_info_print (info, outf, "<$cpu_type$$cpu_type$>");
	fclose(outf); outf = NULL;
	
	fail_unless (strcmp (output, "<AuthenticAMDAuthenticAMD>") == 0);
}
END_TEST

START_TEST (test_uneven_dollar)
{
	info = kernel_info_new ("kernelinfo/full");
	kernel_info_print (info, outf, "$cpu_type");
	fclose(outf); outf = NULL;
	
	fail_unless (strcmp (output, "$cpu_type") == 0);
}
END_TEST

START_TEST (test_hostname)
{
	info = kernel_info_new ("kernelinfo/full");
	kernel_info_print (info, outf, "$hostname$");
	fclose(outf); outf = NULL;
	
	fail_unless (strcmp (output, "darkstar") == 0);
}
END_TEST

START_TEST (test_uptime)
{
	info = kernel_info_new ("kernelinfo/full");
	kernel_info_print (info, outf, "$uptime_f$");
	fclose(outf); outf = NULL;
	
	fail_unless (strcmp (output, "01D 01:01:01") == 0);
}
END_TEST

/* Tests de updating */

START_TEST (test_update_uptime)
{
	FILE *f = fopen ("kernelinfo/update/uptime", "w");
	fputs ("60.0 60.0\n", f);
	fclose(f);

	info = kernel_info_new ("kernelinfo/update");
	kernel_info_print (info, outf, "$uptime_f$|");

	f = fopen ("kernelinfo/update/uptime", "w");
	fputs ("90.0 90.0\n", f);
	fclose(f);

	kernel_info_update (info);

	info = kernel_info_new ("kernelinfo/update");
	kernel_info_print (info, outf, "$uptime_f$");
	fclose(outf); outf = NULL;
	
	fail_unless (strcmp (output, "00D 00:01:00|00D 00:01:30") == 0);

}
END_TEST

START_TEST (test_update_stats)
{
	FILE *f = fopen ("kernelinfo/update/stat", "w");
	fputs ("ctxt 100\n", f);
	fclose(f);

	info = kernel_info_new ("kernelinfo/update");
	kernel_info_print (info, outf, "$context_switches$|");

	f = fopen ("kernelinfo/update/stat", "w");
	fputs ("ctxt 200\n", f);
	fclose(f);

	kernel_info_update (info);

	info = kernel_info_new ("kernelinfo/update");
	kernel_info_print (info, outf, "$context_switches$");
	fclose(outf); outf = NULL;
	
	fail_unless (strcmp (output, "100|200") == 0);

}
END_TEST


/* Armado de la test suite */

Suite *kernel_info_suite (void)
{
	Suite *s = suite_create ("kernel_info");
	TCase *tc_preconditions = tcase_create ("Precondition");
	TCase *tc_functionality = tcase_create ("Functionality");

	/* Precondiciones */
	tcase_add_checked_fixture (tc_preconditions, setup, teardown);
	tcase_add_test_raise_signal (tc_preconditions, test_new_null, SIGABRT);
	suite_add_tcase (s, tc_preconditions);

	tcase_add_checked_fixture (tc_functionality, setup, teardown);
	/* Destructor */
	tcase_add_test (tc_functionality, test_destroy);
	/* Funcionalidad: impresión */
	tcase_add_test (tc_functionality, test_simple_characters_pass);
	tcase_add_test (tc_functionality, test_unknowns_pass);
	tcase_add_test (tc_functionality, test_double_dollar);
	tcase_add_test (tc_functionality, test_substitute);
	tcase_add_test (tc_functionality, test_substitute_multiple);
	tcase_add_test (tc_functionality, test_uneven_dollar);
	/* Funcionalidad: tags */
	tcase_add_test (tc_functionality, test_hostname);
	tcase_add_test (tc_functionality, test_uptime);
	/* Funcionalidad: update */
	tcase_add_test (tc_functionality, test_update_uptime);
	tcase_add_test (tc_functionality, test_update_stats);
	suite_add_tcase (s, tc_functionality);

	return s;
}

